当数据库启动之后,buffer pool也分配好了,只不过这个时候,Buffer Pool中的一个一个的缓存页都是空的,里面什么都没有,要等数据库运行起来之后,当我们要对数据执行增删改查的操作的时候,才会把数据对应的页从磁盘文件里读取出来,放入Buffer Pool中的缓存页中。
我们怎么知道哪些缓存页是空闲的
因为默认情况下磁盘上的数据页和缓存页是一 一对应起来的,都是16KB,一个数据页对应一个缓存页。
所以我们必须要知道Buffer Pool中哪些缓存页是空闲的状态。
所以数据库会为Buffer Pool设计一个free链表,他是一个双向链表数据结构,这个free链表里,每个节点就是一个空闲的缓存页的描述数据块的地址,也就是说,只要你一个缓存页是空闲的,那么他的描述数据块就会被放入这个free链表中。
刚开始数据库启动的时候,可能所有的缓存页都是空闲的,因为此时可能是一个空的数据库,一条数据都没有,所以此时所有缓存页的描述数据块,都会被放入这个free链表中
除此之外,这个free链表有一个基础节点,他会引用链表的头节点和尾节点,里面还存储了链表中有多少个描述数据块的节点,也就是有多少个空闲的缓存页。
如何将磁盘上的页读取到Buffer Pool的缓存页中去
首先,我们需要从free链表里获取一个描述数据块,然后就可以对应的获取到这个描述数据块对应的空闲缓存页
接着我们就可以把磁盘上的数据页读取到对应的缓存页里去,同时把相关的一些描述数据写入缓存页的描述数据块里去,比如这个数据页所属的表空间之类的信息,最后把那个描述数据块从free链表里去除就可以了,如下图所示。
怎么知道数据页有没有被缓存?
我们在执行增删改查的时候,肯定是先看看这个数据页有没有被缓存,如果没被缓存就走上面的逻辑,从free链表中找到一个空闲的缓存页,从磁盘上读取数据页写入缓存页,写入描述数据,从free链表中移除这个描述数据块。
但是如果数据页已经被缓存了,那么就会直接使用了。
所以数据库还会有一个哈希表数据结构,他会用表空间号+数据页号,作为一个key,然后缓存页的地址作为value。
当要使用一个数据页的时候,通过表空间号+数据页号作为key去这个哈希表里查一下,如果没有就读取数据页,如果已经有了,就说明数据页已经被缓存了
也就是说,每次你读取一个数据页到缓存之后,都会在这个哈希表中写入一个key-value对,key就是表空间号+数据页号,value就是缓存页的地址,那么下次如果你再使用这个数据页,就可以从哈希表里直接读取出来他已经被放入一个缓存页了。
思考
我们在操作数据库时,一般使用的是SQL操作表和数据,在MySQL内部实际上操作的是表空间和数据页,这两者有什么关系呢?
其实简单的说:一个是逻辑概念,一个是物理概念。
表、列和行,都是逻辑概念,我们只知道数据库里有一个表,表里有几个字段,有多少行,但是这些表里的数据,在数据库的磁盘上如何存储的,我们是不关注的,所以他们都是逻辑上的概念。
表空间、数据页,这些东西,都是物理上的概念,实际上在物理层面,你的表里的数据都放在一个表空间中,表空间是由一堆磁盘上的数据文件组成的,这些数据文件里都存放了你表里的数据,这些数据是由一个一个的数据页组织起来的,这些都是物理层面的概念,这就是他们之间的区别。